function ListNode(val, next, prev) {
    this.val = val || null;
    this.next = next || null;
    this.prev = prev || null;
}

/**
 * https://leetcode-cn.com/problems/design-circular-deque/
 * Initialize your data structure here. Set the size of the deque to be k.
 * @param {number} k
 */
 var MyCircularDeque = function(k = 0) {
    this._dummyHead = new ListNode();
    this._dummyTail = new ListNode(null, null, this._dummyHead);
    this._dummyHead.next = this._dummyTail;

    this._size = 0;
    this._capcity = k;
};

/**
 * Adds an item at the front of Deque. Return true if the operation is successful. 
 * @param {number} value
 * @return {boolean}
 */
MyCircularDeque.prototype.insertFront = function(value) {
    if (this.isFull()) {
        return false;
    }
    const newNode = new ListNode(value, this._dummyHead.next, this._dummyHead);
    this._dummyHead.next.prev = newNode;
    this._dummyHead.next = newNode;
    this._size++;
    return true;
};

/**
 * Adds an item at the rear of Deque. Return true if the operation is successful. 
 * @param {number} value
 * @return {boolean}
 */
MyCircularDeque.prototype.insertLast = function(value) {
    if (this.isFull()) {
        return false;
    }
    const newNode = new ListNode(value, this._dummyTail, this._dummyTail.prev);
    this._dummyTail.prev.next = newNode;
    this._dummyTail.prev = newNode;
    this._size++;
    return true;
};

/**
 * Deletes an item from the front of Deque. Return true if the operation is successful.
 * @return {boolean}
 */
MyCircularDeque.prototype.deleteFront = function() {
    if (this.isEmpty()) {
        return false;
    }
    const newHead = this._dummyHead.next.next;
    this._dummyHead.next = newHead;
    newHead.prev = this._dummyHead;
    this._size--;
    return true;
};

/**
 * Deletes an item from the rear of Deque. Return true if the operation is successful.
 * @return {boolean}
 */
MyCircularDeque.prototype.deleteLast = function() {
    if (this.isEmpty()) {
        return false;
    }
    const newTail = this._dummyTail.prev.prev;
    this._dummyTail.prev = newTail;
    newTail.next = this._dummyTail;
    this._size--;
    return true;
};

/**
 * Get the front item from the deque.
 * @return {number}
 */
MyCircularDeque.prototype.getFront = function() {
    if (this.isEmpty()) {
        return -1;
    }
    return this._dummyHead.next.val;
};

/**
 * Get the last item from the deque.
 * @return {number}
 */
MyCircularDeque.prototype.getRear = function() {
    if (this.isEmpty()) {
        return -1;
    }
    return this._dummyTail.prev.val;
};

/**
 * Checks whether the circular deque is empty or not.
 * @return {boolean}
 */
MyCircularDeque.prototype.isEmpty = function() {
    return this._dummyHead.next === this._dummyTail;
}
/**
 * Checks whether the circular deque is full or not.
 * @return {boolean}
 */
MyCircularDeque.prototype.isFull = function() {
    return this._size === this._capcity;
};

/**
 * Your MyCircularDeque object will be instantiated and called as such:
 * var obj = new MyCircularDeque(k)
 * var param_1 = obj.insertFront(value)
 * var param_2 = obj.insertLast(value)
 * var param_3 = obj.deleteFront()
 * var param_4 = obj.deleteLast()
 * var param_5 = obj.getFront()
 * var param_6 = obj.getRear()
 * var param_7 = obj.isEmpty()
 * var param_8 = obj.isFull()
 */